/*
    TA2.C
*/

#include <p_std.h>
#include <p_sys.h>
#include <wlib.h>
#include <hwif.h>

LOCAL_D TEXT *cmds[]=
    {
    "rReset score",
    "lLimits",
    "mMode",
    "tTiming",
    "xExit",
    NULL
    };

#define TABLES_ITEMS       5

LOCAL_D H_MENU_DATA mdata[]=
    {
    "Tables",TABLES_ITEMS,
    NULL
    };

GLDEF_D TEXT ** _cmds=(&cmds[0]);
GLDEF_D H_MENU_DATA * _mdata=(&mdata[0]);


LOCAL_D UINT MainWid;

typedef struct
    {
    UWORD TableEnd;
    UWORD MaxTable;
    UWORD Tested;
    UWORD Correct;
    UWORD Timing;
    UWORD Mode;
    } TSTATE;

LOCAL_D TSTATE state={12,12,0,0,5,1};

LOCAL_D TEXT *EnvName="TABLES";
#define ENV_NAME_LEN 6


LOCAL_C VOID DrawLine(INT j,TEXT *pb)
    {
    P_RECT box;

    box.tl.x=4;
    box.br.x=189-4;
    box.tl.y=4+9*j;
    box.br.y=box.tl.y+9;
    gPrintBoxText(&box,8,G_TEXT_ALIGN_CENTRE,0,pb,p_slen(pb));
    }

LOCAL_C VOID DisplayScores(VOID)
    {
    TEXT buf[40];

    p_atos(&buf[0],"Score:  %u correct out of %u",state.Correct,state.Tested);
    DrawLine(0,&buf[0]);
    }

LOCAL_C VOID DisplayMode(VOID)
    {
    TEXT *pb;
    TEXT buf[40];

    if (state.Mode==1)
        pb="Testing all tables";
    else
        {
        p_atos(&buf[0],"Testing %d times table",state.Mode);
        pb=(&buf[0]);
        }
    DrawLine(1,pb);
    }

LOCAL_C VOID DisplayLimits(VOID)
    {
    TEXT buf[40];

    p_atos(&buf[0],"(up to %d times %d)",
                (state.Mode==1? state.MaxTable: state.Mode),state.TableEnd);
    DrawLine(2,&buf[0]);
    }

LOCAL_C VOID DrawButton(INT state)
    {
    P_RECT box;

    box.tl.x=34+36;
    box.br.x=34+36+38;
    box.tl.y=47;
    box.br.y=47+14;
    wDrawButton(&box,"Enter",state);
    }

LOCAL_C VOID DisplayPressButton(VOID)
    {
    gPrintText(34,56,"Press",5);
    DrawButton(FALSE);
    gPrintText(34+36+38+6,56,"to test",7);
    }

LOCAL_C VOID Display(VOID)
    {
    DisplayScores();
    DisplayMode();
    DisplayLimits();
    DisplayPressButton();
    }

LOCAL_C VOID ResetScore(VOID)
    {
    if (!state.Tested)
        {
        wInfoMsg("No score to reset");
        return;
        }
    if (uOpenDialog("Reset score to zero"))
        return;
    if (uAddButtonList("No",-'n',"Yes",'y',NULL))
        return;
    if (uRunDialog()=='y')
        {
        state.Tested=0;
        state.Correct=0;
        DisplayScores();
        }
    }

LOCAL_C VOID ChangeLimits(VOID)
    {
    LONG lTableEnd;
    LONG lMaxTable;
    H_DI_NUMBER end;
    H_DI_NUMBER last;

    lTableEnd=state.TableEnd;
    lMaxTable=state.MaxTable;
    if (uOpenDialog("Limits for testing"))
        return;
    end.value=(&lTableEnd);
    end.low=10;
    end.high=99;
    if (uAddDialogItem(H_DIALOG_NUMBER,"Tables end at",&end))
        return;
    last.value=(&lMaxTable);
    last.low=2;
    last.high=99;
    if (uAddDialogItem(H_DIALOG_NUMBER,"Highest table",&last))
        return;
    if (uRunDialog()<=0)
        return;
    state.TableEnd=lTableEnd;
    state.MaxTable=lMaxTable;
    if (state.Mode>state.MaxTable)
        state.Mode=state.MaxTable;
    DisplayMode();
    DisplayLimits();
    }

LOCAL_C VOID ChangeTiming(VOID)
    {
    LONG lTiming;
    H_DI_NUMBER tim;

    lTiming=state.Timing;
    if (uOpenDialog("Timing"))
        return;
    tim.value=(&lTiming);
    tim.low=1;
    tim.high=20;
    if (uAddDialogItem(H_DIALOG_NUMBER,"Number of seconds allowed",&tim))
        return;
    if (uRunDialog()<=0)
        return;
    state.Timing=lTiming;
    }

LOCAL_C VOID ChangeMode(VOID)
    {
    H_DI_CHOICE ch;
    INT j;
    TEXT buf[20];

    if (uOpenDialog("Mode"))
        return;
    if (uBeginDCL(&ch))
        return;
    if (uGrowDCL(&ch,"All tables"))
        return;
    for (j=2; j<=state.MaxTable; j++)
        {
        p_atos(&buf[0],"%d times table",j);
        if (uGrowDCL(&ch,&buf[0]))
            return;
        }
    if (uAddDCL("Test which tables",&state.Mode,&ch))
        return;
    if (uRunDialog()<=0)
        return;
    DisplayMode();
    DisplayLimits();
    }

LOCAL_C VOID ExitApplication(VOID)
    {
    uErrorValue(p_setenviron(EnvName,ENV_NAME_LEN,&state,sizeof(TSTATE)));
    p_exit(0);
    }

LOCAL_C VOID ManageCommand(INT index)
    {
    switch (index)
        {
    case 0:
        ResetScore();
        break;
    case 1:
        ChangeLimits();
        break;
    case 2:
        ChangeMode();
        break;
    case 3:
        ChangeTiming();
        break;
    case 4:
        ExitApplication();
        }
    }

LOCAL_C VOID TryExecuteCommand(INT keycode)
    {
    keycode=uLocateCommand(keycode);
    if (keycode>=0)
        ManageCommand(keycode);
    }

LOCAL_C VOID MakeButtonDance(VOID)
    {
    DrawButton(TRUE);
    wFlush();
    p_sleep(2);
    DrawButton(FALSE);
    wFlush();
    p_sleep(2);
    }

LOCAL_C VOID DoTest(VOID)
    {
    MakeButtonDance();
    state.Tested++;
    state.Correct++;
    DisplayScores();
    }

LOCAL_C VOID MainLoop(VOID)
    {
    INT ret;
    WMSG_KEY key;

    FOREVER
        {
        uGetKey(&key);
        if (key.keycode&W_EVENT_KEY)
            {
            if (key.keycode==CONS_EVENT_COMMAND)
                ExitApplication();
            }
        else if (key.keycode&W_SPECIAL_KEY)
            TryExecuteCommand(key.keycode&(~W_SPECIAL_KEY));
        else if (key.keycode==W_KEY_MENU && !(key.modifiers&W_CTRL_MODIFIER))
            {
            ret=uPresentMenus();
            if (ret>0)
                TryExecuteCommand(ret);
            }
        else if (key.keycode==W_KEY_RETURN)
            DoTest();
        }
    }

LOCAL_C VOID ReadState(VOID)
    {
    INT len;
    UBYTE buf[P_ENVMAX];

    len=p_getenviron(EnvName,ENV_NAME_LEN,&buf[0]);
    if (len<0 || len!=sizeof(TSTATE))
        return;
    p_bcpy(&state,&buf[0],sizeof(TSTATE));
    }

LOCAL_C VOID ReduceScreenSize(VOID)
    {
    W_WINDATA wd;

    wd.extent.tl.x=wd.extent.tl.y=0;
    wd.extent.width=189;
    wd.extent.height=80;
    wSetWindow(MainWid,W_WIN_EXTENT,&wd);
    if (uErrorValue(wCheckPoint()))
        p_exit(0);
    }

LOCAL_C VOID CreateGC(VOID)
    {
    INT hgc;

    hgc=gCreateGC0(uFindMainWid());
    if (hgc<0)
        p_exit(hgc);
    }

LOCAL_C VOID SpecificInit(VOID)
    {
    hCrackCommandLine();
    MainWid=uFindMainWid();
    ReduceScreenSize();
    CreateGC();
    gBorder(W_BORD_CORNER_4);
    wsEnable();
    ReadState();
    Display();
    }

GLDEF_C VOID main(VOID)
    {
    uCommonInit();
    SpecificInit();
    MainLoop();
    }
